#include <iostream>
#include <mutex>
#include <pthread.h>
#include <vector>
#include <string>
#include <unistd.h>
#include "Mutex.hpp"

using namespace std;
static pthread_mutex_t Lock = PTHREAD_MUTEX_INITIALIZER; // 如果这把锁是全局的，那么可以直接这样初始化

class ThreadData // 想把锁传递给线程
{
public:
    ThreadData(string threadname, pthread_mutex_t *mutex_p) : _threadname(threadname), _mutex_p(mutex_p)
    {
    }
    ~ThreadData()
    {
    }

public:
    string _threadname;
    pthread_mutex_t *_mutex_p;
};

int tickets = 10000;

void *getTicket(void *args)
{
    // 加锁和解锁的过程是多个线程串行执行的，程序变慢了！
    // 锁只是规定互斥访问，没有规定必须谁先执行
    // 锁就是真实的然后多个执行流竞争的结果

    {
        ThreadData *td = static_cast<ThreadData *>(args);
        while (true)
        {
            LockGuard lockguard(&Lock); // RAII风格的加锁！ 对象的生命周期结束，自动释放
            // pthread_mutex_lock(td->_mutex_p);
            if (tickets > 0)
            {
                usleep(1000);
                cout << td->_threadname << "正在抢票： " << tickets << endl;
                tickets--;
                // pthread_mutex_unlock(td->_mutex_p);
            }
            else
            {
                // pthread_mutex_unlock(td->_mutex_p);// 没有这一步：死锁
                break;
            }
            // 抢完锁就完了吗？当然不是
            // usleep(1000); // 形成一个订单发给客户
        }
    }
    return nullptr;
}

int main()
{
    // pthread_mutex_t lock;// 公共的锁
    // pthread_mutex_init(&lock,nullptr);

#define num 4

    vector<pthread_t> tids(num); // 已经有了4个tid
    for (int i = 1; i <= num; i++)
    {
        char namebuffer[64];
        snprintf(namebuffer, sizeof(namebuffer), "thread %d", i);
        ThreadData *td = new ThreadData(namebuffer, &Lock);
        pthread_create(&tids[i - 1], nullptr, getTicket, (void *)td);
    }

    for (const auto &tid : tids)
    {
        pthread_join(tid, nullptr);
    }
    // pthread_t t1,t2,t3,t4;
    // pthread_create(&t1,nullptr,getTicket,(void*)"thread 1");
    // pthread_create(&t2,nullptr,getTicket,(void*)"thread 1");
    // pthread_create(&t3,nullptr,getTicket,(void*)"thread 1");
    // pthread_create(&t4,nullptr,getTicket,(void*)"thread 1");

    // pthread_join(t1,nullptr);
    // pthread_join(t2,nullptr);
    // pthread_join(t3,nullptr);
    // pthread_join(t4,nullptr);

    // pthread_mutex_destroy(&lock);
    return 0;
}

////////////////////////////////////////////函数调用接口////////////////////////////////////

// int pthread_mutex_destroy(pthread_mutex_t *mutex);
// int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
// int pthread_mutex_lock(pthread_mutex_t *mutex);
// int pthread_mutex_trylock(pthread_mutex_t *mutex); 试着加锁，申请成功继续向后执行，申请不成功非阻塞
// int pthread_mutex_unlock(pthread_mutex_t *mutex);

////////////////////////////////////////////锁的概念////////////////////////////////////

// 1.怎么看待锁
// a.锁，本身就是一个共享资源
// b.锁本身是安全了，-- 原子性
// c.如果申请成功，就继续向后执行，如果申请成功，执行流会阻塞！
// d.谁申请成功，谁向后执行
// e.持有锁的时候，也能被切换 -- 抱着锁被切换，其他执行流没有锁还是没办法向后执行
// f.使用锁的时候，要保持锁的粒度非常小！

// 2.如何理解加锁和解锁的本质  -- 加锁的过程是原子的
// a.CPU内寄存器只有一套所有执行流共享
// b.CPU内寄存器的内容，是每个执行流私有的，运行时上下文
// c.怎么实现原子性？ -- 内存中本来有个小整数：1，%al寄存器；线程A进来在寄存器上放个0，再对内存的数和寄存器的数交换(原子)，所以自己的上下文中就是1，持有锁！
// 线程B：把0放入寄存器，内存的寄存器的数交换，上下文还是0，没有锁！

// 3.如果我们想简单的使用，该如何进行封装设计